package com.fanml.service;

import com.alibaba.fastjson.JSONObject;
import com.fanml.entty.FileInfo;
import com.fanml.entty.constant.ConstantValue;
import com.fanml.entty.enums.MsgTypeEnum;
import com.fanml.entty.netty.Message;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @title: NettyClientUploadHandle
 * @Author fanml
 * @describe: //TODO
 * @Date: 2021/7/4 17:39
 * @Version 1.0
 */
public class NettyClientUploadHandle extends ChannelInboundHandlerAdapter {

    private File file;//上传的文件

    private int blockIndex;//当前块号

    private FileChannel localFileChannel;//本地文件管道

    private int blockCount;//文件总块数

    private ChannelHandlerContext ctx;//上下文

    /**
     * @param filePath 要上传的文件路径
     * @return
     * @throws FileNotFoundException
     * @author fanml
     * @date 2021/7/4 17:39
     */
    public NettyClientUploadHandle(String filePath) throws FileNotFoundException {

        file = new File(filePath);
        if (!file.exists())
            throw new FileNotFoundException(filePath);
        RandomAccessFile r = new RandomAccessFile(file, "r");
        localFileChannel = r.getChannel();
        long fileLength = file.length();
        blockCount = (int) (fileLength % ConstantValue.BLOCK_SIZE == 0 ? fileLength / ConstantValue.BLOCK_SIZE : fileLength / ConstantValue.BLOCK_SIZE + 1);

    }


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        this.ctx = ctx;
    }

    /**
     * 连接建立
     *
     * @param ctx
     * @return
     * @throws
     * @author fanml
     * @date 2021/7/4 17:41
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //建立连接发送第一块
        putMaxFile(1);
    }

    /**
     * 收到消息的逻辑
     *
     * @param ctx
     * @param msg
     * @return
     * @throws Exception
     * @author fanml
     * @date 2021/7/4 17:42
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        if (!(msg instanceof Message)) {
            return;
        }
        Message message = null;
        try {
            message = (Message) msg;
            //会话id
            String sessionId = message.getSessionId();
            if (MsgTypeEnum.UPLOAD == message.getMsgTypeEnum()) {
                byte[] msgBody = message.getMsgBody();
                String s = new String(msgBody, CharsetUtil.UTF_8);
                JSONObject respJson = JSONObject.parseObject(s);
                if (respJson.getInteger("retCode") == 0) {
                    //获取服务端返回的块号
                    blockIndex = respJson.getInteger("data").intValue();
                    //上传文件块
                    putMaxFile(blockIndex);
                }
            } else if (MsgTypeEnum.RESPONSE == message.getMsgTypeEnum()) {
                if (blockIndex == blockCount) {
                    System.out.println("文件: " + file.getPath() + "已推送结束");
                    localFileChannel.close();
                    ctx.close();
                }
            }
        } finally {
            if (message != null)
                ReferenceCountUtil.release(message);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("发生异常了----------------------------");
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 上传文件
     *
     * @param blockIndex 文件块号
     * @return void
     * @throws IOException
     * @author fanml
     * @date 2021/7/4 17:45
     */
    private void putMaxFile(int blockIndex) throws IOException {

        MappedByteBuffer mappedByteBuffer;
        Message message;
        byte[] fileBlockByte;
        System.out.println("当前推送文件块号: " + blockIndex + "/" + blockCount);
        //文件分块起始位置
        long position = (blockIndex - 1) * ConstantValue.BLOCK_SIZE;
        //文件块长度
        long size = blockIndex == blockCount ? file.length() - (blockIndex - 1) * ConstantValue.BLOCK_SIZE : ConstantValue.BLOCK_SIZE;
        mappedByteBuffer = localFileChannel.map(FileChannel.MapMode.READ_ONLY, position, size);
        fileBlockByte = new byte[(int) size];
        for (int offset = 0; offset < size; offset++) {
            byte b = mappedByteBuffer.get();
            fileBlockByte[offset] = b;
        }
        FileInfo fileInfo = new FileInfo(file.getName(), file.length(), blockCount, blockIndex, fileBlockByte);
        String jsonString = JSONObject.toJSONString(fileInfo);
        message = new Message(null, MsgTypeEnum.UPLOAD, jsonString.getBytes(CharsetUtil.UTF_8));
        ctx.writeAndFlush(message);
        mappedByteBuffer.clear();
    }
}
